/*
 * FtpContext.cpp
 *
 *  Created on: 2012-12-28
 *      Author: yangentao@gmail.com
 */
#include <iostream>
#include "FtpContext.h"
#include "../yet/LineParse.h"

namespace ftp {
using namespace yet;

bool myFtpLog(LogMsg msg) {
	if (msg.tag == "ftpsend") {
		if (msg.level == logError) {
			cout << "[S] " << msg.msg << endl;
		} else {
			cout << "[S] " << msg.msg << endl;
		}
	} else if (msg.tag == "ftpecho") {
		if (msg.level == logError) {
			cout << "[R] " << msg.msg << endl;
		} else {
			cout << "[R] " << msg.msg << endl;
		}
	} else if (msg.tag == "ftp") {
		if (msg.level == logError) {
			cout << "[I] " << msg.msg << endl;
		} else {
			cout << "[I] " << msg.msg << endl;
		}
	}
	return true;
}
FtpContext::FtpContext() {
	port = 21;
	pasvPort = 0;
	listDataOK = false;
	nlstDataOK = false;
	buf.init(128);
	logConn = slog.pushLogHandler(myFtpLog, "ftp", "ftpsend", "ftpecho");
}

FtpContext::~FtpContext() {
	logConn.disconnect();
}
bool FtpContext::connect() {
	ftplog << "connecting..." << end;
	if (!sock.createTcpSocket()) {
		return false;
	}
	SocketOption opt(sock.sock);
	opt.setExclusiveAddrUse(TRUE);
	if (0 != sock.connect(host, port)) {
		sock.close();
		return false;
	}
	ftplog << "connected." << end;
	return true;
}
bool FtpContext::recvControl(Packet* p) {
	int n = sock.recv(buf.buffer, buf.length);
	if (n == 0) {
		sock.close();
		ftplog << "Server Closed" << end;
		return false;
	}
	if (n < 0) {
		SocketError e;
		sock.close();
		ftplog << err << p->cmdName() << " " << e.getCode() << sp << e.getCodeName() << end;
		return false;

	}
	//n > 0

	p->appendResponse(string(buf.buffer, n));
	if (p->isOk() || p->isNext()) {
		for (int i = 0; i < p->responseCount(); ++i) {
			for (size_t k = 0; k < p->getLines(i).size(); ++k) {
				ftpecho << p->getLines(i)[k] << end;
			}
		}
		return true;
	}
	if (p->isError() || p->isFailed()) {
		for (int i = 0; i < p->responseCount(); ++i) {
			for (size_t k = 0; k < p->getLines(i).size(); ++k) {
				ftpecho << err << p->getLines(i)[k] << end;
			}
		}
		return false;
	}
	return recvControl(p);
}

bool FtpContext::send(string s, bool isOOB) {
	int n = sock.send(s.c_str(), s.length(), isOOB ? MSG_OOB : 0);
	if (n < 0) {
		SocketError e;
		sock.close();
		ftplog << err << e.getCode() << sp << e.getCodeName() << end;
		return false;
	}
	if (n == s.length()) {
		return true;
	}
	s = s.substr(n);
	return send(s, isOOB);
}
bool FtpContext::sendControl(Packet* p) {
	string s = p->getRequest();
	ftpsend << trimCrlf(s) << end;
	if (!send(s, (p->cmd == FTP_ABOR))) {
		ftplog << err << "Send Failed" << end;
		return false;
	}
	return true;
}
bool FtpContext::sendRecvControl(Packet* p) {
	if (!sendControl(p)) {
		return false;
	}
	if (!recvControl(p)) {
		return false;
	}
	return true;
}

string FtpContext::getServerName() {
	return connectResponse;
}
bool FtpContext::isSupportCommand(string serverCommand) {
	return serverCommands.find(serverCommand) != serverCommands.end();
}
vector<string> FtpContext::getNlstItems() {
	vector<string> v;
	if (nlstDataOK) {
		LineParse p(nlstData);
		for (int i = 0; i < p.getLineCount(); ++i) {
			string line = p.getLineText(i);
			line = trim(line);
			if (!line.empty()) {
				v.push_back(line);
			}
		}
	}
	return v;
}
bool FtpContext::isUnix() {
	return systData.find("UNIX") != string::npos;
}
bool FtpContext::isMsDos() {
	return systData.find("DOS") != string::npos;
}
} /* namespace yet */
